#include <stdio.h>
#include <string.h>
#define Max 100
#define HELLO "hello, world"
#define OW "C Program language is invented \
in 1970s"
#define TWO 2
#define FOUR TWO*TWO
// 带参数的宏
#define SQUARE(X) X*X
// 最好参数中使用()
#define SQUARE2(X) (X)*(X)
// 也可以没有参数
#define gerchar() getc(stdin)
// 多行的宏
#define PRINT_NUMS_TO_PRODUCT(a, b) { \
  int product = (a) * (b); \
  for (int i = 0; i< product;i++) { \
    printf("%d\n", i); \
  } \
}
//　#运算符 替换后的值为字符串
#define STR(x) #x
#define XNAME(n) "x"#n
#define MK_ID(n) i##n
// 后面是多余的参数，注意...只能写到最后面
#define X(a, b, ...) (10*(a) + 20*(b)), __VA_ARGS__
// 取消宏
#define LIMIT 400
#undef LIMIT
// 形式一
// #include <foo.h> // 加载系统提供的文件
// 形式二
#include "foo.h" // 加载用户提供的文件

// if endif
#if 0
  const double pi = 3.1415; // 不会执行
#endif
// else
#define FOO 1
#if FOO
  // printf("defined\n");
#else
  printf("not defined\n");
#endif
// elif
#if HAPPY_FACTOR == 0
  // printf("I'm not happy!\n");
#elif HAPPY_FACTOR == 1
  printf("I'm just regular\n");
#else
  printf("I'm extra happy!\n");
#endif
// 检查某个宏是否定义过
#ifdef EXTRA_HAPPY
  printf("I'm extra happy!\n");
#endif

#ifdef EXTRA_HAPPY
  printf("I'm extra happy!\n");
#else
  // printf("I'm just regular\n");
#endif

#ifdef MAVIS
  #include "foo.h"
  #define STABLES 1
#else
  #include "bar.h"
  #define STABLES 2
#endif

#if defined FOO
  int x100 = 2;
#elif defined BAR
  x100 = 3;
#endif

#if defined IBMPC
  #include "ibmpc.h"
#elif defined MAC
  #include "mac.h"
#else
  #include "general.h"
#endif
// #ifndef...#endif指令跟#ifdef...#endif正好相反。它用来判断,如果某个宏没有被定义过,则执行指定的操作。
#ifdef EXTRA_HAPPY
  printf("I'm extra happy!\n");
#endif

#ifndef EXTRA_HAPPY
  // printf("I'm just regular\n");
#endif
// #ifndef常用于防止重复加载
#ifndef MYHEADER_H
  #define MYHEADER_H
  #include "myheader.h"
#endif
// c语言的预定义宏
// __DATE__：编译日期，格式为“Mmm dd yyyy”的字符串（比如 Nov 23 2021）。
// __TIME__：编译时间，格式为“hh:mm:ss”。
// __FILE__：当前文件名。
// __LINE__：当前行号。
// __func__：当前正在执行的函数名。该预定义宏必须在函数作用域使用。
// __STDC__：如果被设为1，表示当前编译器遵循 C 标准。
// __STDC_HOSTED__：如果被设为1，表示当前编译器可以提供完整的标准库；否则被设为0（嵌入式系统的标准库常常是不完整的）。
// __STDC_VERSION__：编译所使用的 C 语言版本，是一个格式为yyyymmL的长整数，C99 版本为“199901L”，C11 版本为“201112L”，C17 版本为“201710L”。
// 将下一行的行号重置为 300
#line 300
// #line还可以改掉预定义宏__FILE__，将其改为自定义的文件名。
#line 300 "newfilename"
// #error指令用于让预处理器抛出一个错误，终止编译。
#if __STDC_VERSION__ != 201112L
//  #error Not C11
#endif
// #pragma指令用来修改编译器属性。
// 使用 C99 标准
#pragma c9x on
int main(void) {
  printf("%s\n", HELLO);
  int z = SQUARE(2);
  // 原样替换
  // 3 + 4*3 + 4
  printf("%d\n", SQUARE(3+4)); //输出19
  // 等同于 printf("%s\n", STR("3.13159"));
  printf("%s\n", STR(3.13159));
  // 输出 x4
  printf("%s\n", XNAME(4));
  int MK_ID(1), MK_ID(2), MK_ID(3);
  // 替换成
  // int i1, i2, i3;
  printf("This function: %s\n", __func__);
  printf("This file: %s\n", __FILE__);
  printf("This line: %d\n", __LINE__);
  printf("Compiled on: %s %s\n", __DATE__, __TIME__);
  printf("C Version: %ld\n", __STDC_VERSION__);

  return 0;
}
